home *** CD-ROM | disk | FTP | other *** search
/ Risc World 5 / Risc World 5.iso / SOFTWARE / Issue3 / Games / xrick / !xrick / src / c / ents < prev    next >
Text File  |  2004-06-24  |  13KB  |  521 lines

  1. /*
  2.  * xrick/src/ents.c
  3.  *
  4.  * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved.
  5.  *
  6.  * The use and distribution terms for this software are contained in the file
  7.  * named README, which can be found in the root of this distribution. By
  8.  * using this software in any fashion, you are agreeing to be bound by the
  9.  * terms of this license.
  10.  *
  11.  * You must not remove this notice, or any other, from this software.
  12.  */
  13.  
  14. #include <stdlib.h>
  15.  
  16. #include "system.h"
  17. #include "config.h"
  18. #include "game.h"
  19. #include "ents.h"
  20. #include "debug.h"
  21.  
  22. #include "e_bullet.h"
  23. #include "e_bomb.h"
  24. #include "e_rick.h"
  25. #include "e_them.h"
  26. #include "e_bonus.h"
  27. #include "e_box.h"
  28. #include "e_sbonus.h"
  29. #include "rects.h"
  30. #include "maps.h"
  31. #include "draw.h"
  32.  
  33. /*
  34.  * global vars
  35.  */
  36. ent_t ent_ents[ENT_ENTSNUM + 1];
  37. rect_t *ent_rects = NULL;
  38.  
  39.  
  40. /*
  41.  * prototypes
  42.  */
  43. static void ent_addrect(S16, S16, U16, U16);
  44. static U8 ent_creat1(U8 *);
  45. static U8 ent_creat2(U8 *, U16);
  46.  
  47.  
  48. /*
  49.  * Reset entities
  50.  *
  51.  * ASM 2520
  52.  */
  53. void
  54. ent_reset(void)
  55. {
  56.   U8 i;
  57.  
  58.   E_RICK_STRST(E_RICK_STSTOP);
  59.   e_bomb_lethal = FALSE;
  60.  
  61.   ent_ents[0].n = 0;
  62.   for (i = 2; ent_ents[i].n != 0xff; i++)
  63.     ent_ents[i].n = 0;
  64. }
  65.  
  66.  
  67. /*
  68.  * Create an entity on slots 4 to 8 by using the first slot available.
  69.  * Entities of type e_them on slots 4 to 8, when lethal, can kill
  70.  * other e_them (on slots 4 to C) as well as rick.
  71.  *
  72.  * ASM 209C
  73.  *
  74.  * e: anything, CHANGED to the allocated entity number.
  75.  * return: TRUE/OK FALSE/not
  76.  */
  77. static U8
  78. ent_creat1(U8 *e)
  79. {
  80.   /* look for a slot */
  81.   for (*e = 0x04; *e < 0x09; (*e)++)
  82.     if (ent_ents[*e].n == 0) {  /* if slot available, use it */
  83.       ent_ents[*e].c1 = 0;
  84.       return TRUE;
  85.     }
  86.  
  87.   return FALSE;
  88. }
  89.  
  90.  
  91. /*
  92.  * Create an entity on slots 9 to C by using the first slot available.
  93.  * Entities of type e_them on slots 9 to C can kill rick when lethal,
  94.  * but they can never kill other e_them.
  95.  *
  96.  * ASM 20BC
  97.  *
  98.  * e: anything, CHANGED to the allocated entity number.
  99.  * m: number of the mark triggering the creation of the entity.
  100.  * ret: TRUE/OK FALSE/not
  101.  */
  102. static U8
  103. ent_creat2(U8 *e, U16 m)
  104. {
  105.   /* make sure the entity created by this mark is not active already */
  106.   for (*e = 0x09; *e < 0x0c; (*e)++)
  107.     if (ent_ents[*e].n != 0 && ent_ents[*e].mark == m)
  108.       return FALSE;
  109.  
  110.   /* look for a slot */
  111.   for (*e = 0x09; *e < 0x0c; (*e)++)
  112.     if (ent_ents[*e].n == 0) {  /* if slot available, use it */
  113.       ent_ents[*e].c1 = 2;
  114.       return TRUE;
  115.     }
  116.  
  117.   return FALSE;
  118. }
  119.  
  120.  
  121. /*
  122.  * Process marks that are within the visible portion of the map,
  123.  * and create the corresponding entities.
  124.  *
  125.  * absolute map coordinate means that they are not relative to
  126.  * map_frow, as any other coordinates are.
  127.  *
  128.  * ASM 1F40
  129.  *
  130.  * frow: first visible row of the map -- absolute map coordinate
  131.  * lrow: last visible row of the map -- absolute map coordinate
  132.  */
  133. void
  134. ent_actvis(U8 frow, U8 lrow)
  135. {
  136.     U16 m;
  137.     U8 e;
  138.     U16 y;
  139.  
  140.     /*
  141.     * go through the list and find the first mark that
  142.     * is visible, i.e. which has a row greater than the
  143.     * first row (marks being ordered by row number).
  144.     */
  145.     for (m = map_submaps[game_submap].mark;
  146.         map_marks[m].row != 0xff && map_marks[m].row < frow;
  147.         m++);
  148.  
  149.     if (map_marks[m].row == 0xff)  /* none found */
  150.         return;
  151.  
  152.     /*
  153.     * go through the list and process all marks that are
  154.     * visible, i.e. which have a row lower than the last
  155.     * row (marks still being ordered by row number).
  156.     */
  157.     for (;
  158.         map_marks[m].row != 0xff && map_marks[m].row < lrow;
  159.         m++) {
  160.  
  161.         /* ignore marks that are not active */
  162.         if (map_marks[m].ent & MAP_MARK_NACT)
  163.             continue;
  164.  
  165.         /*
  166.          * allocate a slot to the new entity
  167.          *
  168.          * slot type
  169.          *  0   available for e_them (lethal to other e_them, and stops entities
  170.          *      i.e. entities can't move over them. E.g. moving blocks. But they
  171.          *      can move over entities and kill them!).
  172.          *  1   xrick
  173.          *  2   bullet
  174.          *  3   bomb
  175.          * 4-8  available for e_them, e_box, e_bonus or e_sbonus (lethal to
  176.          *      other e_them, identified by their number being >= 0x10)
  177.          * 9-C  available for e_them, e_box, e_bonus or e_sbonus (not lethal to
  178.          *      other e_them, identified by their number being < 0x10)
  179.          *
  180.          * the type of an entity is determined by its .n as detailed below.
  181.          *
  182.          * 1               xrick
  183.          * 2               bullet
  184.          * 3               bomb
  185.          * 4, 7, a, d      e_them, type 1a
  186.          * 5, 8, b, e      e_them, type 1b
  187.          * 6, 9, c, f      e_them, type 2
  188.          * 10, 11          box
  189.          * 12, 13, 14, 15  bonus
  190.          * 16, 17          speed bonus
  191.          * >17             e_them, type 3
  192.          * 47              zombie
  193.          */
  194.  
  195.         if (!(map_marks[m].flags & ENT_FLG_STOPRICK)) {
  196.             if (map_marks[m].ent >= 0x10) {
  197.                 /* boxes, bonuses and type 3 e_them go to slot 4-8 */
  198.                 /* (c1 set to 0 -> all type 3 e_them are sleeping) */
  199.                 if (!ent_creat1(&e)) continue;
  200.             }
  201.             else {
  202.                 /* type 1 and 2 e_them go to slot 9-c */
  203.                 /* (c1 set to 2) */
  204.                 if (!ent_creat2(&e, m)) continue;
  205.             }
  206.         }
  207.         else {
  208.             /* entities stopping rick (e.g. blocks) go to slot 0 */
  209.             if (ent_ents[0].n) continue;
  210.             e = 0;
  211.             ent_ents[0].c1 = 0;
  212.         }
  213.  
  214.     /*
  215.      * initialize the entity
  216.      */
  217.     ent_ents[e].mark = m;
  218.     ent_ents[e].flags = map_marks[m].flags;
  219.     ent_ents[e].n = map_marks[m].ent;
  220.  
  221.     /*
  222.      * if entity is to be already running (i.e. not asleep and waiting
  223.      * for some trigger to move), then use LETHALR i.e. restart flag, right
  224.      * from the beginning
  225.      */
  226.     if (ent_ents[e].flags & ENT_FLG_LETHALR)
  227.       ent_ents[e].n |= ENT_LETHAL;
  228.  
  229.     ent_ents[e].x = map_marks[m].xy & 0xf8;
  230.  
  231.     y = (map_marks[m].xy & 0x07) + (map_marks[m].row & 0xf8) - map_frow;
  232.     y <<= 3;
  233.     if (!(ent_ents[e].flags & ENT_FLG_STOPRICK))
  234.       y += 3;
  235.     ent_ents[e].y = y;
  236.  
  237.     ent_ents[e].xsave = ent_ents[e].x;
  238.     ent_ents[e].ysave = ent_ents[e].y;
  239.  
  240.     /*ent_ents[e].w0C = 0;*/  /* in ASM code but never used */
  241.  
  242.     ent_ents[e].w = ent_entdata[map_marks[m].ent].w;
  243.     ent_ents[e].h = ent_entdata[map_marks[m].ent].h;
  244.     ent_ents[e].sprbase = ent_entdata[map_marks[m].ent].spr;
  245.     ent_ents[e].sprite = (U8)ent_entdata[map_marks[m].ent].spr;
  246.     ent_ents[e].step_no_i = ent_entdata[map_marks[m].ent].sni;
  247.     ent_ents[e].trigsnd = (U8)ent_entdata[map_marks[m].ent].snd;
  248.  
  249.     /*
  250.      * FIXME what is this? when all trigger flags are up, then
  251.      * use .sni for sprbase. Why? What is the point? (This is
  252.      * for type 1 and 2 e_them, ...)
  253.      *
  254.      * This also means that as long as sprite has not been
  255.      * recalculated, a wrong value is used. This is normal, see
  256.      * what happens to the falling guy on the right on submap 3:
  257.      * it changes when hitting the ground.
  258.      */
  259. #define ENT_FLG_TRIGGERS \
  260. (ENT_FLG_TRIGBOMB|ENT_FLG_TRIGBULLET|ENT_FLG_TRIGSTOP|ENT_FLG_TRIGRICK)
  261.     if ((ent_ents[e].flags & ENT_FLG_TRIGGERS) == ENT_FLG_TRIGGERS
  262.     && e >= 0x09)
  263.       ent_ents[e].sprbase = (U8)(ent_entdata[map_marks[m].ent].sni & 0x00ff);
  264. #undef ENT_FLG_TRIGGERS
  265.  
  266.     ent_ents[e].trig_x = map_marks[m].lt & 0xf8;
  267.     ent_ents[e].latency = (map_marks[m].lt & 0x07) << 5;  /* <<5 eq *32 */
  268.  
  269.     ent_ents[e].trig_y = 3 + 8 * ((map_marks[m].row & 0xf8) - map_frow +
  270.                   (map_marks[m].lt & 0x07));
  271.  
  272.     ent_ents[e].c2 = 0;
  273.     ent_ents[e].offsy = 0;
  274.     ent_ents[e].ylow = 0;
  275.  
  276.     ent_ents[e].front = FALSE;
  277.  
  278.   }
  279. }
  280.  
  281.  
  282. /*
  283.  * Add a tile-aligned rectangle containing the given rectangle (indicated
  284.  * by its MAP coordinates) to the list of rectangles. Clip the rectangle
  285.  * so it fits into the display zone.
  286.  */
  287. static void
  288. ent_addrect(S16 x, S16 y, U16 width, U16 height)
  289. {
  290.   S16 x0, y0;
  291.   U16 w0, h0;
  292.  
  293.   /*sys_printf("rect %#04x,%#04x %#04x %#04x ", x, y, width, height);*/
  294.  
  295.   /* align to tiles */
  296.   x0 = x & 0xfff8;
  297.   y0 = y & 0xfff8;
  298.   w0 = width;
  299.   h0 = height;
  300.   if (x - x0) w0 = (w0 + (x - x0)) | 0x0007;
  301.   if (y - y0) h0 = (h0 + (y - y0)) | 0x0007;
  302.  
  303.   /* clip */
  304.   if (draw_clipms(&x0, &y0, &w0, &h0)) {  /* do not add if fully clipped */
  305.     /*sys_printf("-> [clipped]\n");*/
  306.     return;
  307.   }
  308.  
  309.   /*sys_printf("-> %#04x,%#04x %#04x %#04x\n", x0, y0, w0, h0);*/
  310.  
  311. #ifdef GFXST
  312.   y0 += 8;
  313. #endif
  314.  
  315.   /* get to screen */
  316.   x0 -= DRAW_XYMAP_SCRLEFT;
  317.   y0 -= DRAW_XYMAP_SCRTOP;
  318.  
  319.   /* add rectangle to the list */
  320.   ent_rects = rects_new(x0, y0, w0, h0, ent_rects);
  321. }
  322.  
  323.  
  324. /*
  325.  * Draw all entities onto the frame buffer.
  326.  *
  327.  * ASM 07a4
  328.  *
  329.  * NOTE This may need to be part of draw.c. Also needs better comments,
  330.  * NOTE and probably better rectangles management.
  331.  */
  332. void
  333. ent_draw(void)
  334. {
  335.   U8 i;
  336. #ifdef ENABLE_CHEATS
  337.   static U8 ch3 = FALSE;
  338. #endif
  339.   S16 dx, dy;
  340.  
  341.   draw_tilesBank = map_tilesBank;
  342.  
  343.   /* reset rectangles list */
  344.   rects_free(ent_rects);
  345.   ent_rects = NULL;
  346.  
  347.   /*sys_printf("\n");*/
  348.  
  349.   /*
  350.    * background loop : erase all entities that were visible
  351.    */
  352.   for (i = 0; ent_ents[i].n != 0xff; i++) {
  353. #ifdef ENABLE_CHEATS
  354.     if (ent_ents[i].prev_n && (ch3 || ent_ents[i].prev_s))
  355. #else
  356.     if (ent_ents[i].prev_n && ent_ents[i].prev_s)
  357. #endif
  358.       /* if entity was active, then erase it (redraw the map) */
  359.       draw_spriteBackground(ent_ents[i].prev_x, ent_ents[i].prev_y);
  360.   }
  361.  
  362.   /*
  363.    * foreground loop : draw all entities that are visible
  364.    */
  365.   for (i = 0; ent_ents[i].n != 0xff; i++) {
  366.     /*
  367.      * If entity is active now, draw the sprite. If entity was
  368.      * not active before, add a rectangle for the sprite.
  369.      */
  370. #ifdef ENABLE_CHEATS
  371.     if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite))
  372. #else
  373.     if (ent_ents[i].n && ent_ents[i].sprite)
  374. #endif
  375.       /* If entitiy is active, draw the sprite. */
  376.       draw_sprite2(ent_ents[i].sprite,
  377.            ent_ents[i].x, ent_ents[i].y,
  378.            ent_ents[i].front);
  379.   }
  380.  
  381.   /*
  382.    * rectangles loop : figure out which parts of the screen have been
  383.    * impacted and need to be refreshed, then save state
  384.    */
  385.   for (i = 0; ent_ents[i].n != 0xff; i++) {
  386. #ifdef ENABLE_CHEATS
  387.     if (ent_ents[i].prev_n && (ch3 || ent_ents[i].prev_s)) {
  388. #else
  389.     if (ent_ents[i].prev_n && ent_ents[i].prev_s) {
  390. #endif
  391.       /* (1) if entity was active and has been drawn ... */
  392. #ifdef ENABLE_CHEATS
  393.       if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite)) {
  394. #else
  395.       if (ent_ents[i].n && ent_ents[i].sprite) {
  396. #endif
  397.     /* (1.1) ... and is still active now and still needs to be drawn, */
  398.     /*       then check if rectangles intersect */
  399.     dx = abs(ent_ents[i].x - ent_ents[i].prev_x);
  400.     dy = abs(ent_ents[i].y - ent_ents[i].prev_y);
  401.     if (dx < 0x20 && dy < 0x16) {
  402.       /* (1.1.1) if they do, then create one rectangle */
  403.       ent_addrect((ent_ents[i].prev_x < ent_ents[i].x)
  404.               ? ent_ents[i].prev_x : ent_ents[i].x,
  405.               (ent_ents[i].prev_y < ent_ents[i].y)
  406.               ? ent_ents[i].prev_y : ent_ents[i].y,
  407.               dx + 0x20, dy + 0x15);
  408.     }
  409.     else {
  410.       /* (1.1.2) else, create two rectangles */
  411.       ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15);
  412.       ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15);
  413.     }
  414.       }
  415.       else
  416.     /* (1.2) ... and is not active anymore or does not need to be drawn */
  417.     /*       then create one single rectangle */
  418.     ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15);
  419.     }
  420. #ifdef ENABLE_CHEATS
  421.     else if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite)) {
  422. #else
  423.     else if (ent_ents[i].n && ent_ents[i].sprite) {
  424. #endif
  425.       /* (2) if entity is active and needs to be drawn, */
  426.       /*     then create one rectangle */
  427.       ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15);
  428.     }
  429.  
  430.     /* save state */
  431.     ent_ents[i].prev_x = ent_ents[i].x;
  432.     ent_ents[i].prev_y = ent_ents[i].y;
  433.     ent_ents[i].prev_n = ent_ents[i].n;
  434.     ent_ents[i].prev_s = ent_ents[i].sprite;
  435.   }
  436.  
  437. #ifdef ENABLE_CHEATS
  438.   ch3 = game_cheat3;
  439. #endif
  440. }
  441.  
  442.  
  443. /*
  444.  * Clear entities previous state
  445.  *
  446.  */
  447. void
  448. ent_clprev(void)
  449. {
  450.   U8 i;
  451.  
  452.   for (i = 0; ent_ents[i].n != 0xff; i++)
  453.     ent_ents[i].prev_n = 0;
  454. }
  455.  
  456. /*
  457.  * Table containing entity action function pointers.
  458.  */
  459. void (*ent_actf[])(U8) = {
  460.   NULL,        /* 00 - zero means that the slot is free */
  461.   e_rick_action,   /* 01 - 12CA */
  462.   e_bullet_action,  /* 02 - 1883 */
  463.   e_bomb_action,  /* 03 - 18CA */
  464.   e_them_t1a_action,  /* 04 - 2452 */
  465.   e_them_t1b_action,  /* 05 - 21CA */
  466.   e_them_t2_action,  /* 06 - 2718 */
  467.   e_them_t1a_action,  /* 07 - 2452 */
  468.   e_them_t1b_action,  /* 08 - 21CA */
  469.   e_them_t2_action,  /* 09 - 2718 */
  470.   e_them_t1a_action,  /* 0A - 2452 */
  471.   e_them_t1b_action,  /* 0B - 21CA */
  472.   e_them_t2_action,  /* 0C - 2718 */
  473.   e_them_t1a_action,  /* 0D - 2452 */
  474.   e_them_t1b_action,  /* 0E - 21CA */
  475.   e_them_t2_action,  /* 0F - 2718 */
  476.   e_box_action,  /* 10 - 245A */
  477.   e_box_action,  /* 11 - 245A */
  478.   e_bonus_action,  /* 12 - 242C */
  479.   e_bonus_action,  /* 13 - 242C */
  480.   e_bonus_action,  /* 14 - 242C */
  481.   e_bonus_action,  /* 15 - 242C */
  482.   e_sbonus_start,  /* 16 - 2182 */
  483.   e_sbonus_stop  /* 17 - 2143 */
  484. };
  485.  
  486.  
  487. /*
  488.  * Run entities action function
  489.  *
  490.  */
  491. void
  492. ent_action(void)
  493. {
  494.   U8 i, k;
  495.  
  496.   IFDEBUG_ENTS(
  497.     sys_printf("xrick/ents: --------- action ----------------\n");
  498.     for (i = 0; ent_ents[i].n != 0xff; i++)
  499.       if (ent_ents[i].n) {
  500.     sys_printf("xrick/ents: slot %#04x, entity %#04x", i, ent_ents[i].n);
  501.     sys_printf(" (%#06x, %#06x), sprite %#04x.\n",
  502.            ent_ents[i].x, ent_ents[i].y, ent_ents[i].sprite);
  503.       }
  504.     );
  505.  
  506.   for (i = 0; ent_ents[i].n != 0xff; i++) {
  507.     if (ent_ents[i].n) {
  508.       k = ent_ents[i].n & 0x7f;
  509.       if (k == 0x47)
  510.     e_them_z_action(i);
  511.       else if (k >= 0x18)
  512.         e_them_t3_action(i);
  513.       else
  514.     ent_actf[k](i);
  515.     }
  516.   }
  517. }
  518.  
  519.  
  520. /* eof */
  521.